//自定义封装组件：下拉多选框
<template>
  <el-select
      v-model="selectedOptions"
      multiple
      placeholder="请选择"
      :popper-appened-to-body="false"
      style="width: 100%"
      @remove-tag="removeTag"
  >
    <el-option
        v-for="item in options"
        :key="item.value"
        :label="item.label"
        :value="item.value"
    >
      <el-checkbox
          v-model="item.check"
          @change="isChecked(item)">{{ item.label }}
      </el-checkbox>
    </el-option>
    <div class="is-all">
      <div @click="selectAll(true)" style="border-radius: 3px;background-color: rgba(100,108,255,0.17)">全选</div>
      <div @click="selectAll(false)" style="border-radius: 3px;background-color: rgba(100,108,255,0.17)">反选</div>
    </div>
  </el-select>
</template>

<script setup lang="ts">
import {ref, watch} from "vue";
//选框属性数据类型
type SelectItem = {
  value: string | number
  label: string
  check: boolean
}

//接收父组件传递的参数
let props = defineProps({
  options: {
    type: Array<SelectItem>,
    required: true
  },
  width: {
    type: Number,
    default() {
      return 220
    }
  },
  bindValue: {
    type: Array<string | number>,
    default() {
      return []
    }
  }
})

//注册事件
const emit = defineEmits(['selected']);
//下拉框数据
let selectedOptions = ref<Array<string | number>>([])
//下拉框点击事件
const isChecked = (item) => {
  if (item.check && selectedOptions.value.indexOf(item.value) == -1) {
    selectedOptions.value.push(item.value)
  } else if (!item.check) {
    //再次点击取消选中
    selectedOptions.value.forEach((elm, idx) => {
      if (elm == item.value) {
        selectedOptions.value.splice(idx, 1)
      }
    })
  }
  emit('selected', selectedOptions.value)
}
//删除图标
const removeTag = (value: any) => {
  props.options?.forEach((elm) => {
    if (elm.value == value) {
      elm.check = false
    }
  })
  emit('selected', selectedOptions.value)
}

function selectAll(isAll: boolean) {
  if (isAll) {
    selectedOptions.value = []
    props.options.forEach((item: SelectItem) => {
      item.check = true
      selectedOptions.value.push(item.value)
    })
  } else {
    let arr: Array<string | number> = []
    props.options?.forEach((item) => {
      item.check = !item.check
      if (!selectedOptions.value.includes(item.value)) {
        arr.push(item.value)
      }
    })
    selectedOptions.value = arr
  }
  emit('selected', selectedOptions.value)
}

//清空数据
const clear = () => {
  selectedOptions.value = []
}
//将方法暴露给外部组件使用
defineExpose({
  clear
})
watch(
    () => props.bindValue,
    () => {
      //设置选中的值
      selectedOptions.value = props.bindValue
      //设置勾选状态
      props.bindValue.forEach(item => {
        props.options?.find(dom => {
          if (dom.value == item) {
            dom.check = true
          }
        })
      })
    },
    {
      immediate: true
    }
)
</script>

<style scoped>
.is-all {
  display: flex;
  padding-left: 10px;

  div {
    cursor: pointer;
    margin: 6px 10px;
    transition: 0.2s;
    &:hover {
      opacity: 0.7;
    }
  }
}
</style>